#include "GetElementPtrInstruction.h"
#include "Type.h"
#include <sstream>

// GetElementPtrInstruction.cpp
GetElementPtrInstruction::GetElementPtrInstruction(Module * module,
                                                   Function * func,
                                                   Value * ptr,
                                                   std::vector<Value *> indices,
                                                   const Type * type)                      // 修改为 const Type*
    : Instruction(func, IRInstOperator::IRINST_OP_ARRAY_ACCESS, const_cast<Type *>(type)), // 移除 const
      ptr(ptr), indices(indices), dimensionsCalculated(false)
{
    // 使用 const_cast 确保类型兼容
    Type * nonConstType = const_cast<Type *>(type);
    Type * ptrType = new PointerType(nonConstType);
    result = func->newTempVariable(ptrType);
    result->isarrayresult = true;
    // 补全：把ptr和indices全部加入操作数列表
    addOperand(ptr);
    for (auto idx: indices) {
        addOperand(idx);
    }
}

void GetElementPtrInstruction::toString(std::string & str)
{
    if (indices.empty() || !ptr || !result)
        return;

    Type * ptr_type = ptr->getType();
    PointerType * _ptr_type = static_cast<PointerType *>(ptr_type);
    std::ostringstream oss;

    // 用于保存需要插入的load指令字符串
    std::vector<std::string> loadInsts;

    if (ptr->getType()->isPointerType() && !_ptr_type->isArray()) {

        Value * loaded = func->newTempVariable(_ptr_type);
        std::string loadStr = loaded->getIRName() + " = load " + loaded->getType()->toString() + ", " +
                              ptr->getType()->toString() + "* " + ptr->getIRName();
        loadInsts.push_back(loadStr);
        ptr = loaded;
    }

    if (_ptr_type->isArray()) {
        oss << result->getIRName() << " = getelementptr inbounds " << ptr_type->toString() << ", "
            << ptr_type->toString() << "* " << ptr->getIRName();
    } else {
        oss << result->getIRName() << " = getelementptr inbounds " << _ptr_type->getPointeeType()->toString() << ", "
            << ptr_type->toString() << " " << ptr->getIRName();
    }

    for (size_t i = 0; i < indices.size(); ++i) {
        Value * idx = indices[i];
        if (!idx) {
            oss << ", i32 0";
            continue;
        }
        // 判断是否为LocalVariable
        if (dynamic_cast<LocalVariable *>(idx) || dynamic_cast<GlobalVariable *>(idx)) {
            // 生成临时变量名
            Value * tmpVar = func->newTempVariable(idx->getType());
            std::string tmpName = tmpVar->getIRName();
            // 生成load指令
            std::string loadStr = tmpName + " = load i32, i32* " + idx->getIRName();
            loadInsts.push_back(loadStr);
            // GEP使用临时变量
            oss << ", i32 " << tmpName;
        } else {
            oss << ", i32 " << idx->getIRName();
        }
    }

    // 先输出所有load指令，再输出GEP指令
    std::ostringstream final;
    for (const auto & l: loadInsts) {
        final << l << "\n";
    }
    final << oss.str();
    str = final.str();
}

std::vector<int> GetElementPtrInstruction::getArrayDimensions()
{
    if (!dimensionsCalculated) {
        calculateArrayDimensions();
    }
    return arrayDimensions;
}

std::string GetElementPtrInstruction::getArrayDimensionString()
{
    std::vector<int> dimensions = getArrayDimensions();

    if (dimensions.empty()) {
        return "not_array";
    }

    std::string result;
    for (size_t i = 0; i < dimensions.size(); ++i) {
        if (i > 0) {
            result += " x ";
        }
        result += std::to_string(dimensions[i]);
    }

    return result;
}

int GetElementPtrInstruction::getTotalElementCount()
{
    std::vector<int> dimensions = getArrayDimensions();

    if (dimensions.empty()) {
        return 0;
    }

    int total = 1;
    for (int dim: dimensions) {
        total *= dim;
    }

    return total;
}

bool GetElementPtrInstruction::hasValidArrayDimensions() const
{
    return dimensionsCalculated && !arrayDimensions.empty();
}

int GetElementPtrInstruction::getDimensionCount()
{
    return getArrayDimensions().size();
}

void GetElementPtrInstruction::calculateArrayDimensions()
{
    arrayDimensions.clear();

    if (!ptr || !ptr->getType() || !ptr->getType()->isPointerType()) {
        dimensionsCalculated = true;
        return;
    }

    const PointerType * ptrType = static_cast<const PointerType *>(ptr->getType());

    // 如果是指向数组的指针，需要获取指向的数组类型
    if (!ptrType->isArray()) {
        // 检查是否是指向数组的指针
        const Type * pointeeType = ptrType->getPointeeType();
        if (pointeeType && pointeeType->isPointerType()) {
            ptrType = static_cast<const PointerType *>(pointeeType);
        } else {
            dimensionsCalculated = true;
            return;
        }
    }

    // 递归获取所有维度信息
    const PointerType * currentType = ptrType;
    while (currentType && currentType->isArray()) {
        arrayDimensions.push_back(currentType->getLength());

        // 获取下一层类型
        const Type * nextType = currentType->getElementType();
        if (nextType && nextType->isPointerType()) {
            currentType = static_cast<const PointerType *>(nextType);
        } else {
            break;
        }
    }

    dimensionsCalculated = true;
}
